/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package GraphPackage;

import GUIUtilities.ColorUtilities;
import GUIUtilities.LabelManager;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 *
 * @author Heather
 */
public class HorizontalBarGraph extends BarGraph
{
  private BarGraphBars barsPanel;
  private Image buffer;
  private Graphics bufferG;
  private int numberOfXAxisValuesExcludingZero = 10;
  // where along the graph width the yAxis should be drawn
  private double yAxisPercentage = 0;

  public HorizontalBarGraph()
  {
    this.setBackground(bgColor);

    // setup the bars panel
    calculateVariables();
    barsPanel = new BarGraphBars();

    this.setLayout(null);
    add(barsPanel);
    barsPanel.setLayout(null);
    barsPanel.setSize(getSize());
    barsPanel.setLocation(0, 0);
    setDefaultLabelTexts();
    resizeAllLabels();
    setupLabelLocations();
    setupComponentOrder();
  }

  public HorizontalBarGraph(int numberOfBars)//, int width, int height)
  {
    this.setBackground(bgColor);

    // setup the bars panel
    calculateVariables();
    barsPanel = new BarGraphBars();

    for (int i = 0; i < numberOfBars; i++)
    {
      barValues.add(50.0);
      Color c = ColorUtilities.getRandomColorWithConstraints(MIN_COLOR_CONSTRAINT, 230);//MAX_COLOR_CONSTRAINT);
      currentBarColors.add(c);
      defaultBarColors.add(c);
      barLabels.add(new JLabel());
      xAxisLabels.add(new JLabel());
    }

    this.setLayout(null);
    add(barsPanel);
    barsPanel.setLayout(null);
    barsPanel.setSize(getSize());
    barsPanel.setLocation(0, 0);
    setDefaultLabelTexts();
    resizeAllLabels();
    setupLabelLocations();
    setupComponentOrder();
  }

  protected void calculateVariables()
  {
    super.calculateVariables();
    maxDimension = graphWidth * (Math.abs(maxValue) / (Math.abs(minValue) + Math.abs(maxValue)));
    minDimension = graphWidth * (Math.abs(minValue) / (Math.abs(minValue) + Math.abs(maxValue)));
    yAxisPercentage = Math.abs(minValue) / (Math.abs(minValue) + Math.abs(maxValue));
  }

  // makes sure all the components are overlapping properly
  private void setupComponentOrder()
  {
    removeAll();

    for (int i = 0; i < getBarLabels().size(); i++)
    {
      add(getBarLabels().get(i));
    }

    for (int i = 0; i < xAxisLabels.size(); i++)
    {
      add(xAxisLabels.get(i));
    }

    for (int i = 0; i < yAxisLabels.size(); i++)
    {
      add(yAxisLabels.get(i));
    }

    add(graphTitleLabel);
    add(barsPanel);
  }

  // sets the locations of the labels
  /*
   *     private Vector<JLabel> barLabels = new Vector<JLabel>();
  private Vector<JLabel> xAxisLabels = new Vector<JLabel>();
  private Vector<JLabel> yAxisLabels = new Vector<JLabel>();
   */
  private void setupLabelLocations()
  {
    // these represent the locations of the labels.
    int x = 0;
    int y = 0;

    // placing the top title label
    x = (getSize().width / 2) - (graphTitleLabel.getSize().width / 2);
    y = (int) topLabelBorder / 2;
    graphTitleLabel.setLocation(x, y);
    Dimension titleD = LabelManager.getLabelDimensions(graphTitleLabel);
    graphTitleLabel.setSize(titleD);
    graphTitleLabel.setPreferredSize(titleD);

    // place the yAxisLabels
    calculateVariables();

    int barValueIncrement = (int) (maxValue / numberOfXAxisValuesExcludingZero);
    int barHeightIncrement = (int) ((barValueIncrement / maxValue) * graphHeight);
    // start placing labels starting from the top
    for (int i = 0; i <= numberOfXAxisValuesExcludingZero; i++)
    {
      JLabel currentYLabel = yAxisLabels.get(i);//numberOfYAxisValues - 1 - i);
      Dimension d = LabelManager.getLabelDimensions(currentYLabel);
      x = (int) leftLabelBorder - d.width;
      y = (int) topLabelBorder + (barHeightIncrement * i) - d.height / 2;
      currentYLabel.setLocation(x, y);
    }

    // place the xAxisLabels
    // this offset is to keep the label from starting at the axis
    int numberOfBars = getBarValues().size();
    int xLabelRightOffset = 5;
    int labelCenterInterval = (int) graphHeight / (numberOfBars + 1);
    double barWidth = (graphHeight - getTotalBarSpacing()) / getBarValues().size();
    double barSpace = getTotalBarSpacing() / (getBarValues().size() + 2);
    for (int i = 0; i < numberOfBars; i++)
    {
      JLabel l = getBarLabels().get(i);
      Dimension d = LabelManager.getLabelDimensions(l);

      double barValue = getBarValues().get(i);
      int labelX = 0;
      if (barValue >= 0)
      // 5 added for some spacing
      {
        labelX = (int) ((graphWidth * yAxisPercentage) + leftLabelBorder) + 5;
      }
      else
      {
        labelX = (int) ((graphWidth * yAxisPercentage) + leftLabelBorder - 5 - d.width);
      }

      int labelY = (int) ((i * (barWidth + barSpace)) + topLabelBorder + barSpace + barWidth / 2 - d.height / 2);

      l.setLocation(labelX, labelY);
    }
  }

  // resizes a label based on its font
  public void resizeLabel(JLabel l)
  {
    Dimension lD = LabelManager.getLabelDimensions(l);
    l.setSize(lD);
  }

  // resizes all the labels
  public void resizeAllLabels()
  {
    for (int i = 0; i < getBarLabels().size(); i++)
    {
      resizeLabel(getBarLabels().get(i));
    }

    for (int i = 0; i < xAxisLabels.size(); i++)
    {
      resizeLabel(xAxisLabels.get(i));
    }

    for (int i = 0; i < yAxisLabels.size(); i++)
    {
      resizeLabel(yAxisLabels.get(i));
    }

    resizeLabel(graphTitleLabel);
  }

  public void setNumberOfBars(int numberOfBars)
  {
    currentBarColors.clear();
    defaultBarColors.clear();
    getBarValues().clear();
    getCurrentBarColors().clear();
    getBarLabels().clear();
    xAxisLabels.clear();

    for (int i = 0; i < numberOfBars; i++)
    {
      getBarValues().add(0.0);
      Color c = ColorUtilities.getRandomColorWithConstraints(MIN_COLOR_CONSTRAINT, 230);//MAX_COLOR_CONSTRAINT);
      getCurrentBarColors().add(c);
      defaultBarColors.add(c);
      getBarLabels().add(new JLabel());
      xAxisLabels.add(new JLabel());
    }

    barsPanel.setSize(getSize());
    barsPanel.setLayout(null);
    barsPanel.setLocation(0, 0);
    setupComponentOrder();
  }

  public void setName(String name)
  {
    this.name = name;
  }

  public void setNumberOfYAxisValues(int newNum)
  {
    numberOfXAxisValuesExcludingZero = newNum;
  }

  public void setValue(int index, double newValue)
  {
    getBarValues().set(index, newValue);
  }

  public double getMaxBarValue()
  {
    return maxValue;
  }

  public void setMaxBarValue(double newMaxBarValue)
  {
    maxValue = newMaxBarValue;
  }

  public void setRandomBarValues()
  {
    for (int i = 0; i < getBarValues().size(); i++)
    {
      if (randGen.nextDouble() > .5)
      {
        getBarValues().set(i, randGen.nextDouble() * maxValue);
      }
      else
      {
        getBarValues().set(i, randGen.nextDouble() * minValue);
      }
      //barValues.set(i, maxValue);
      //barValues.set(i, minValue);
      setupLabelLocations();
    }
  }

  public void setRandomBarColors()
  {
    for (int i = 0; i < getBarValues().size(); i++)
    {
      getCurrentBarColors().set(i, new Color(randGen.nextInt(255), randGen.nextInt(255), randGen.nextInt(255)));
    }
  }

  public void setDefaultLabelTexts()
  {
    int numberOfBars = getBarValues().size();

    for (int i = 0; i < numberOfBars; i++)
    {
      getBarLabels().get(i).setText("Bar " + i + ": " + getBarValues().get(i));
    }

    for (JLabel xAxisLabel : xAxisLabels)
    {
      xAxisLabel.setText("bar");
    }

    createYAxisLabels();
    graphTitleLabel.setText("Graph Title");

    setupLabelLocations();
    setupComponentOrder();
  }

  private void createYAxisLabels()
  {
    yAxisLabels.clear();
    // first calculate how many labels will be able to fit based
    // on the maximum bar height
    calculateVariables();

    int barValueIncrement = (int) (maxValue / numberOfXAxisValuesExcludingZero);
    int barHeightIncrement = (int) ((barValueIncrement / maxValue) * maxDimension);
    // start placing labels starting from the top
    for (int i = 0; i <= numberOfXAxisValuesExcludingZero; i++)
    {
      double value = maxValue - (i * barValueIncrement);
      JLabel newYLabel = new JLabel("" + value);
      Dimension d = LabelManager.getLabelDimensions(newYLabel);
      newYLabel.setSize(d);
      newYLabel.setPreferredSize(d);
      yAxisLabels.add(newYLabel);
      add(newYLabel);
    }
  }

  public void setSize(Dimension d)
  {
    super.setSize(d);
    calculateVariables();
    buffer = null;
    barsPanel.setSize(d);
    setupLabelLocations();
    repaint();
  }

  public void setSize(int x, int y)
  {
    super.setSize(x, y);
    calculateVariables();
    buffer = null;
    barsPanel.setSize(x, y);
    setupLabelLocations();
    repaint();
  }

  public void setPreferredSize(Dimension d)
  {
    super.setPreferredSize(d);
    buffer = null;
    barsPanel.setPreferredSize(d);
    repaint();
  }

  /**
   * This is the rectangle stuff that needs to be drawn for bar graphs
   * @author Heather
   */
  public class BarGraphBars extends JPanel
  {

    public BarGraphBars()
    {
      super();
    }

    public void drawGraph()
    {
      // clear the window and setup the graphics objects
      bufferG.setColor(bgColor);
      //bufferG.setColor(Color.red);
      bufferG.fillRect(0, 0, getSize().width, getSize().height);
      Graphics windowG = getGraphics();

      // fill in the graph bg
      Color graphBGColor = Color.white;
      bufferG.setColor(graphBGColor);
      windowG.setColor(graphBGColor);
      bufferG.fillRect((int) leftLabelBorder, (int) topLabelBorder, (int) graphWidth, (int) graphHeight);

      // start filling the lines in
      double barWidth = (graphHeight - getTotalBarSpacing()) / getBarValues().size();
      double barSpace = getTotalBarSpacing() / (getBarValues().size() + 2);
      for (int i = 0; i < getBarValues().size(); i++)
      {
        // setting the proper color
        bufferG.setColor(getCurrentBarColors().get(i));
        windowG.setColor(getCurrentBarColors().get(i));

        // calculate the coordinates
        double x = 0;
        double y = i * (barWidth + barSpace) + topLabelBorder + barSpace;
        double barLength = 0;
        double barValue = getBarValues().get(i);
        if (barValue >= 0)
        {
          x = (int) ((graphWidth * yAxisPercentage) + leftLabelBorder);
          barLength = (barValue / maxValue) * maxDimension;
        }
        else
        {
          barLength = (barValue / minValue) * minDimension;
          x = leftLabelBorder + (graphWidth - barLength - minDimension);
        }

        bufferG.fillRect((int) x, (int) y, (int) barLength, (int) barWidth);
        windowG.fillRect((int) x, (int) y, (int) barLength, (int) barWidth);
      }

      // draw the xAxis
      int xAxisH = 2;
      bufferG.setColor(Color.black);
      windowG.setColor(Color.black);
      bufferG.fillRect((int) leftLabelBorder, (int) (graphHeight + topLabelBorder), (int) (getSize().width - leftLabelBorder - rightBorder), xAxisH);
      windowG.fillRect((int) leftLabelBorder, (int) (graphHeight + topLabelBorder), (int) (getSize().width - leftLabelBorder - rightBorder), xAxisH);

      // draw the yAxis
      int yAxisW = 2;
      bufferG.setColor(Color.black);
      windowG.setColor(Color.black);
      // calculate where the x axis should be
      int yAxisX = (int) ((graphWidth * yAxisPercentage) + leftLabelBorder);
      int yAxisY = (int) topLabelBorder;
      bufferG.fillRect(yAxisX, yAxisY, (int) yAxisW, (int) graphHeight);
      windowG.fillRect(yAxisX, yAxisY, (int) yAxisW, (int) graphHeight);
    }

    public void paint(Graphics g)
    {
      // This creates the buffer
      if (buffer == null)
      {
        int xBound = getSize().width;
        int yBound = getSize().height;

        buffer = this.createImage(xBound, yBound);
        bufferG = buffer.getGraphics();
        bufferG.setColor(Color.white);
        bufferG.fillRect(0, 0, xBound, yBound);
      }
      g.drawImage(buffer, 0, 0, this);
      drawGraph();
    }
  }
}
